#ifndef CSUPBR_INTEGRATOR_H
#define CSUPBR_INTEGRATOR_H

#include "film.h"

namespace csupbr {

    struct Scene;

    struct RenderData {
        RenderData(std::shared_ptr<Film> film,
                   int left, int right, int top, int bottom)
            : film(film), l(left), r(right), t(top), b(bottom) {
            assert(!(left < 0 || right > film->width || top < 0 || bottom > film->height));
        }
        
        std::shared_ptr<Film> film;
        const int l, r, t, b;
        bool is_rendering = false;
    };

    enum IlluminationType {
        GLOBAL = 1 << 0,
        DIRECT = 1 << 1,
        INDIRECT = 1 << 2,
    };

    struct Integrator {
        Integrator(std::shared_ptr<Scene> scene, int spp)
            : scene(scene), spp(spp) {}

        virtual void render(RenderData &rd) const = 0;

        std::shared_ptr<Scene> scene;
        int spp;
        IlluminationType ill_type = IlluminationType::GLOBAL;
        bool is_gamma = true;
    };

    struct Whitted : Integrator {
        Whitted(std::shared_ptr<Scene> scene, int spp, int max_depth)
            : Integrator(scene, spp), max_depth(max_depth) {}
            
        void render(RenderData &rd) const override;

        int max_depth;
    };

    struct PathTracer : Integrator {
        PathTracer(std::shared_ptr<Scene> scene, int spp)
            : Integrator(scene, spp) {}

        void render(RenderData &rd) const override;
    };

}

#endif // !CSUPBR_INTEGRATOR_H